import { ref, reactive, computed, toRaw, isReactive, isRef, } from "vue";
import type { Ref } from "vue";
import { getProperty,isObj } from "@/common/utils";
import { REQUEST_SUCCESS_CODE,DEFAULT_RESPONSE_KEY,DEFAULT_TOTAL_KEY } from '@/env'
import type {PickPromise,PickFrom,KeysOf} from '@/typings/utils'

type PageLoad = (data: {
	loadList: any[],
	addList: any[],
	pageNo?: number,
	limit?: number
}) => { pageNo: number }
const pageLoad: PageLoad = ({
	loadList,
	addList,
	pageNo = 1,
	limit = 20
}) => {
	// 加载内容是否为空
	if (addList.length != 0) {
		// 判断是否为第一次加载 or 第一页加载未满
		if (loadList.length == 0 || loadList.length < limit) {
			// 判断数据是否有变动
			if (loadList.length != addList.length) {
				loadList.splice(0, loadList.length);
			}
		}
		loadList.push(...addList);
		// 加载数据是否够一页
		if (addList.length == limit) {
			pageNo++;
		}
	}
	return { pageNo };
}
interface PromiseData extends Record<any, any> {
    [key: string]: any;
};


interface Option<T extends PromiseData>  {
    responseKey?: string;//列表字段
    responseInterception?: (res: PickFrom<T, KeysOf<T>>) => void;
    params?: Record<string, any> | Ref<Record<string, any>>
    totalKey?: string,//数据总数字段
};






export const useQueryPage = <A extends (data: any) => Promise<PromiseData>, T extends PickPromise<ReturnType<A>>, R extends T['rows'],D extends T['data'],DR extends T['data']['rows']>({
	api,
	option,
	pageSize = 20,
}:{ api: A, option?: Option<T>, pageSize?: number }) => {
	//定义分页所需参数，
	const showLoad = ref(false);
	type ListItem = R extends (infer I)[] ? I : D extends (infer I)[] ? I : DR extends (infer I)[] ? I : never
	  const list = reactive<ListItem[]>([]);
	const requestQueue: Array<Record<string, any>|undefined> = [];
	let isRefresh = false
	let page = 1
	const isGet = ref(true)
	const allRequest = async () => {
		let arr = [...requestQueue];
		for (let index in arr) {
			await handleQueryPage(arr[index]);
			requestQueue.splice(Number(index), 1);
		}
	};
	const handleQueryPage = async (params?: Record<string, any>) => {
		if (showLoad.value) {
			// 缓存请求队列，防止上个请求未执行完，导致page不正确
			requestQueue.push(params);
			return;
		}
		if (isGet.value) {
			showLoad.value = true;
			let data:Record<string,any> = {
				pageNum: page,
				pageSize,
			};
			if (option?.params) {
				if (isRef(option.params)&&isObj(option.params.value)) {
					data = {
						...data,
						...option.params.value
					};
				} else {
					data = {
						...data,
						...option.params
					};
				}
			}
			if (params) {
				if (isReactive(params)) {
					data = { ...data, ...toRaw(params) };
				} else {
					data = { ...data, ...params };
				}
			}
			try {
				const res = await api(data) 

				option?.responseInterception?.(res as PickFrom<T, KeysOf<T>>);
				showLoad.value = false;
				if (isRefresh) {
					// 把重置列表的操作放到请求中，可以防止重置列表时，在接口请求完成前，页面出现短暂的无数据现象
					list.splice(0, list.length);
					isRefresh = false
				}
				if (REQUEST_SUCCESS_CODE.includes(res.code)) {
					const addList= getProperty(res, option?.responseKey || DEFAULT_RESPONSE_KEY) as any[]
					let { pageNo } = pageLoad(
						{
							loadList: list,
							addList,
							pageNo: page,
							limit:pageSize
						}
					);
					page = pageNo;

					const dataTotal = getProperty(res, option?.totalKey || DEFAULT_TOTAL_KEY) as number
					// 数据长度与数据总数一致，或在接口无数据总数的情况下,返回的数据长度为0或小于当前请求的pageSize，则视为已经到最后一页了
					if (list.length == dataTotal||!addList.length||addList.length < pageSize) {
						isGet.value = false;
					}
				}

			} catch (e) {
				showLoad.value = false;
				await allRequest();
			}
		}
	};
	const handleInit = () => {
		isGet.value = true;
		page = 1;
		isRefresh = true;
		showLoad.value = false;
		requestQueue.splice(0, requestQueue.length);
	}
	const handleRefresh = async (params?: Record<string, any>) => {
		handleInit()
		await handleQueryPage(params);
	};
	const isEmpty = computed(() => list.length === 0)
	// 无感刷新
	const handleUpdate = async (params?: Record<string, any>) => {
		if(list.length){
			// 当前分页数超过一页，则刷新数据
			const oldPage = page
			const oldPageSize = pageSize
			// const oldIsGet = isGet.value
			pageSize = list.length
			handleInit()
			await handleQueryPage(params);
			page = oldPage
			pageSize = oldPageSize
			// isGet.value = oldIsGet;
		}else{
			// 空数据或未请求数据的情况下，调用handleRefresh
			await handleRefresh(params)
		}
	};
	return {
		showLoad,
		isGet,
		list,
		isEmpty,
		handleQueryPage,
		handleInit,
		handleRefresh,
		handleUpdate
	};
}
